package org.geektimes.configuration.microprofile.config;

import org.apache.commons.lang.StringUtils;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigValue;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;

import java.util.*;

/**
 * @author :   chuan
 * @date :   2021/03/17
 */
public class JavaConfig implements Config {

    private List<ConfigSource> configSources = new LinkedList<>();

    private static Comparator<ConfigSource> configSourceComparator = (o1, o2) -> Integer.compare(o2.getOrdinal(), o1.getOrdinal());

    public JavaConfig() {
        ClassLoader classLoader = getClass().getClassLoader();
        ServiceLoader<ConfigSource> serviceLoader = ServiceLoader.load(ConfigSource.class, classLoader);
        serviceLoader.forEach(configSources::add);

        configSources.sort(configSourceComparator);
    }

    @Override
    public <T> T getValue(String s, Class<T> aClass) {
        if (!getConverter(aClass).isPresent()){
            throw new ClassCastException ("No type converters were found, <"+aClass+"> Not Support!");
        }

        String propertyValue = "";
        for (ConfigSource configSource : configSources) {
            propertyValue = configSource.getValue(s);
            if (StringUtils.isNotBlank(propertyValue)){
                break;
            }
        }

        Converter<T> tConverter = getConverter(aClass).get();
        return tConverter.convert(propertyValue);
    }

    @Override
    public ConfigValue getConfigValue(String s) {
        return null;
    }

    @Override
    public <T> List<T> getValues(String propertyName, Class<T> propertyType) {
        return null;
    }

    @Override
    public <T> Optional<T> getOptionalValue(String s, Class<T> aClass) {
        return Optional.ofNullable(getValue(s, aClass));
    }

    @Override
    public <T> Optional<List<T>> getOptionalValues(String propertyName, Class<T> propertyType) {
        return Optional.ofNullable(getValues(propertyName, propertyType));
    }

    @Override
    public Iterable<String> getPropertyNames() {
        Set<String> names = new LinkedHashSet<>();
        configSources.forEach(configSource -> names.addAll(configSource.getPropertyNames()));
        return names;
    }

    @Override
    public Iterable<ConfigSource> getConfigSources() {
        return Collections.unmodifiableList(configSources);
    }

    @Override
    public <T> Optional<Converter<T>> getConverter(Class<T> aClass) {
        return Optional.ofNullable(DefaultClassTypeConverter.getClassTypeConverter(aClass));
    }

    @Override
    public <T> T unwrap(Class<T> aClass) {
        return null;
    }
}
